#include "sintactico.h"

Sintactico::Sintactico(string dir)
{
    this->lexico = new Lexico(dir);
    this->token_actual = lexico->getNextToken();

    this->tabla_de_tipos= new Tabla_Simbolos();
    this->tabla_de_variables = new Tabla_Simbolos();

    Item_ts *entero = new Item_ts(new Entero(),"ENTERO");
    Item_ts *booleano = new Item_ts(new Booleano(),"BOOLEANO");
    Item_ts *caracter = new Item_ts(new Caracter(),"CARACTER");
    Item_ts *real = new Item_ts(new Real(),"REAL");

    this->tabla_de_tipos->additem(entero);
    this->tabla_de_tipos->additem(booleano);
    this->tabla_de_tipos->additem(caracter);
    this->tabla_de_tipos->additem(real);

    this->num_de_pines.insert (pair<int,bool>(2,false));
    this->num_de_pines.insert (pair<int,bool>(3,false));
    this->num_de_pines.insert (pair<int,bool>(4,false));
    this->num_de_pines.insert (pair<int,bool>(5,false));
    this->num_de_pines.insert (pair<int,bool>(6,false));
    this->num_de_pines.insert (pair<int,bool>(7,false));
    this->num_de_pines.insert (pair<int,bool>(8,false));
    this->num_de_pines.insert (pair<int,bool>(9,false));
    this->num_de_pines.insert (pair<int,bool>(10,false));
    this->num_de_pines.insert (pair<int,bool>(11,false));
    this->num_de_pines.insert (pair<int,bool>(12,false));
    this->num_de_pines.insert (pair<int,bool>(13,false));
    this->num_de_pines.insert (pair<int,bool>(14,false));
    this->num_de_pines.insert (pair<int,bool>(15,false));
    this->num_de_pines.insert (pair<int,bool>(16,false));
    this->num_de_pines.insert (pair<int,bool>(17,false));
    this->num_de_pines.insert (pair<int,bool>(18,false));
    this->num_de_pines.insert (pair<int,bool>(19,false));


}

void Sintactico::match(int tokentype){
    if(this->token_actual->getCod() == tokentype){
        this->token_actual = lexico->getNextToken();
    }else{
        stringstream out;

        out << "Error Sintactico: Se esperaba otro token: "<<this->tokentype.returntokenstring(tokentype)<<"; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
        throw  exception(out.str().c_str());
    }

}

Sentencia* Sintactico::S(){
    Sentencia* instrucciones  =PROGRAMAS();

    match(tokentype.fin_archivo);

    return instrucciones;
}

Sentencia* Sintactico::PROGRAMAS(){
    ENTER_PRI();
    REGISTRO_PRI();
    DECLARAR_PRI(this->tabla_de_variables);
    PIN_PRI(this->tabla_de_variables);
    PROCEDIMIENTO_FUNCION();
    match(tokentype.revInicio);
    ENTER_PRI();
    Sentencia* instrucciones =INTRUCCIONES();
    ENTER_PRI();
    match(tokentype.revFin);
    ENTER_PRI();
    return instrucciones;
}

void Sintactico::PIN(Tabla_Simbolos *ts)
{

    match(tokentype.rev_pin);
    int modo= TIPOSEN();
    PINES(ts,modo);
    PIN_PRI(ts);
}

void Sintactico::PIN_PRI(Tabla_Simbolos *ts)
{

    if(this->token_actual->getCod() == tokentype.rev_pin){

        PIN(ts);

        ENTER();

        PIN_PRI(ts);


    }

}

int Sintactico::TIPOSEN()
{
    if(this->token_actual->getCod() == tokentype.rev_entrada){
        match(tokentype.rev_entrada);
        return 1;
    }else{
        if(this->token_actual->getCod() == tokentype.rev_salida){
            match(tokentype.rev_salida);
            return 0;
        }else{
            return -1;
        }
    }
}

void Sintactico::PINES(Tabla_Simbolos *ts,int modo)
{   string lexema = this->token_actual->getLexema();
    int fila = this->token_actual->getLinea();
    match(tokentype.litIdentificador);
    match(tokentype.pntDosPuntos);
    QString numpin_;
    string numpin = this->token_actual->getLexema();

    numpin_ = numpin_.fromStdString(numpin);

    bool ok;
    match(tokentype.litNumeroEntero);
    if(ts->get(lexema)==0 && this->tabla_de_tipos->get(lexema)==0){
        this->it = this->num_de_pines.find(numpin_.toInt(&ok,10));
        if(this->it != this->num_de_pines.end()){
            if(this->it->second==false){
                Pin *pin = new Pin(numpin_.toInt(&ok,10),modo);
                Item_ts *itms = new Item_ts(pin,lexema);
                ts->additem(itms);
                this->it->second = true;
                PINES_PRI(ts,modo);
            }else{
                stringstream out;
                out<<"El numero de pin ya esta usado "<<lexema<<"// Fila: "<<fila <<endl;
                throw exception(out.str().c_str());
            }
        }else{
            stringstream out;
            out<<"El numero de pin tienen que ser dentro del rango de 2 a 19 "<<lexema<<"// Fila: "<<fila <<endl;
            throw exception(out.str().c_str());
        }

    }else{
        stringstream out;
        out<<"Variable Ya Exite "<<lexema<<"// Fila: "<<fila <<endl;
        throw exception(out.str().c_str());
    }


}

void Sintactico::PINES_PRI(Tabla_Simbolos *ts,int modo)
{
    if(token_actual->getCod() == tokentype.pntComa){
        match(tokentype.pntComa);
        PINES(ts,modo);
    }
}

void Sintactico::ENTER(){
    match(tokentype.enter);
    ENTER_PRI();
}

void Sintactico::ENTER_PRI(){
    if(this->token_actual->getCod() == tokentype.enter){
        ENTER();
    }

}

void Sintactico::REGISTRO(){
    int fila = this->token_actual->getLinea();
    Tabla_Simbolos* tabla_registro = new Tabla_Simbolos();
    match(tokentype.revRegistro);
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);
    DECLARAR_PRI(tabla_registro);
    match(tokentype.revFin);
    match(tokentype.revRegistro);
    Registro *registro = new Registro(tabla_registro,lexema);
    if(this->tabla_de_tipos->get(lexema)==0){
        this->tabla_de_tipos->additem(new Item_ts(registro,lexema));
    }else{
        stringstream out;
        out<<"Variable Ya Exite "<< lexema<<"// Fila: "<<fila<<endl;
        throw exception(out.str().c_str());
    }


}

void Sintactico::REGISTRO_PRI(){
    if(this->token_actual->getCod()==tokentype.revRegistro){
        REGISTRO();
        ENTER();
        REGISTRO_PRI();
    }
}

void Sintactico::DECLARAR(Tabla_Simbolos *ts){
    int fila = this->token_actual->getLinea();
    Tipo_ts* its = TIPORETORNO();
    vector<string> ids;
    ids = LISTAID(ids);
    for(int i=0;i<(int)ids.size();i++){
        if(ts->get(ids.at(i))==0 && this->tabla_de_tipos->get(ids.at(i))==0){
            ts->additem(new Item_ts(its,ids.at(i)));
        }else{
            stringstream out;
            out<<"Variable Ya Exite "<<ids.at(i)<<"// Fila: "<<fila <<endl;
            throw exception(out.str().c_str());
        }
    }

}

void Sintactico::DECLARAR_PRI(Tabla_Simbolos *ts){
    if(token_actual->getCod()==tokentype.revEntero || token_actual->getCod()==tokentype.revReal || token_actual->getCod()==tokentype.revCaracter|| token_actual->getCod()==tokentype.revCadena || token_actual->getCod()==tokentype.litIdentificador||token_actual->getCod()==tokentype.revBooleano || token_actual->getCod()==tokentype.revArreglo){
        DECLARAR(ts);
        ENTER();
        DECLARAR_PRI(ts);
    }else{
        if(this->token_actual->getCod()==tokentype.enter){
            match(tokentype.enter);
            DECLARAR_PRI(ts);
        }
    }
}

void Sintactico::PROCEDIMIENTO_FUNCION(){
    if(token_actual->getCod()==tokentype.revProcedimiento || token_actual->getCod()== tokentype.revFuncion){
        PROCEDIMIENTO_FUNCION_PRI();
        ENTER();
        PROCEDIMIENTO_FUNCION();
    }
}

void Sintactico::PROCEDIMIENTO_FUNCION_PRI(){
    if(token_actual->getCod()==tokentype.revProcedimiento){
        PROCEDIMIENTO();
    }else{
        FUNCION();
    }
}

void Sintactico::PROCEDIMIENTO(){
    int fila = this->token_actual->getLinea();
    Tabla_Simbolos* tabla_procedimiento = new Tabla_Simbolos();
    Tabla_Simbolos* tabla_params = new Tabla_Simbolos();
    Tabla_Simbolos* temp = new Tabla_Simbolos();

    match(tokentype.revProcedimiento);
    string lexema = token_actual->getLexema();
    lexema.append("&FP&");
    match(tokentype.litIdentificador);
    PARAMS(tabla_params);
    ENTER();
    DECLARAR_PRI(tabla_procedimiento);
    match(tokentype.revInicio);
    ENTER_PRI();
    Sentencia *intruccion = INTRUCCIONES();
    ENTER_PRI();
    match(tokentype.revFin);
    if(this->tabla_de_tipos->get(lexema)==0){
        int sizeP = tabla_params->getTable().size();
        int sizePr = tabla_procedimiento->getTable().size();
        if(sizeP>0&&sizePr>0){
            for(int i=0;i<sizeP;i++){
                for(int j=0;j<sizePr;j++){
                    if(tabla_params->getTable().at(i)->getId().compare(tabla_procedimiento->getTable().at(j)->getId())==0){
                        stringstream out;
                        out<<"Variable No se Pueden Llamar igual que los Parametros// Fila: "<<fila<<endl;
                        throw exception(out.str().c_str());
                    }
                }

            }
        }


        vector<Item_ts*> allpro = this->tabla_de_variables->getALL(lexema);
        if(allpro.size()>0){
            for(int i=0;i<(int)allpro.size();i++){
                Procedimiento* item = (Procedimiento*)allpro.at(i)->getTipo();
                int size = item->getParams()->getTable().size();
                int count = 0 ;
                if(size==tabla_params->getTable().size()){
                    for(int j=0;j<size;j++){
                        if(tabla_params->getTable().at(j)->getTipo()->is().compare(item->getParams()->getTable().at(j)->getTipo()->is())==0){
                            count++;
                        }

                    }
                    if(count == size){
                        stringstream out;
                        out<<"Ya existe sobrecarga de funcion o procedimiento "<<lexema<<"// Fila: "<<fila<<endl;
                        throw exception(out.str().c_str());
                    }
                }
            }

        }



        Procedimiento *procedimiento = new Procedimiento(tabla_params,tabla_procedimiento,intruccion);
        this->tabla_de_variables->additem(new Item_ts(procedimiento,lexema));
        for(int i=0;i<sizeP;i++){
            temp->additem(tabla_params->getTable().at(i));
        }
        for(int i=0;i<sizePr;i++){
            temp->additem(tabla_procedimiento->getTable().at(i));
        }
        for(int i=0;i<(int)this->tabla_de_variables->getTable().size();i++){
            if(temp->get(this->tabla_de_variables->getTable().at(i)->getId())==0){
                temp->additem(this->tabla_de_variables->getTable().at(i));
            }
        }
        if(intruccion!=0){

            intruccion->validarSemantica(tabla_de_tipos,temp);
        }
        delete temp;

    }else{
        stringstream out;
        out<<"Variable Ya Exite "<<lexema<<"// Fila: "<<fila<<endl;
        throw exception(out.str().c_str());
    }

}

void Sintactico::FUNCION(){
    int fila = this->token_actual->getLinea();
    Tabla_Simbolos* tabla_funcion = new Tabla_Simbolos();
    Tabla_Simbolos* tabla_params = new Tabla_Simbolos();
    Tabla_Simbolos* temp = new Tabla_Simbolos();
    match(tokentype.revFuncion);
    string lexema = token_actual->getLexema();
    lexema.append("&FP&");
    match(tokentype.litIdentificador);
    PARAMS(tabla_params);
    match(tokentype.pntDosPuntos);
    Tipo_ts *tts = TIPORETORNO();
    ENTER();
    DECLARAR_PRI(tabla_funcion);
    match(tokentype.revInicio);
    ENTER_PRI();
    Sentencia *intruccion =INTRUCCIONES();
    ENTER_PRI();
    match(tokentype.revFin);
    if( this->tabla_de_tipos->get(lexema)==0){
        int sizeP = tabla_params->getTable().size();
        int sizePr = tabla_funcion->getTable().size();
        if(sizeP>0&&sizePr>0){
            for(int i=0;i<sizeP;i++){
                for(int j=0;j<sizePr;j++){
                    if(tabla_params->getTable().at(i)->getId().compare(tabla_funcion->getTable().at(j)->getId())==0){
                        stringstream out;
                        out<<"Variable No se Pueden Llamar igual que los Parametros// Fila: "<<fila<<endl;
                        throw exception(out.str().c_str());
                    }
                }

            }
        }

        vector<Item_ts*> allpro = this->tabla_de_variables->getALL(lexema);
        if(allpro.size()>0){
            for(int i=0;i<(int)allpro.size();i++){
                Funcion* item = (Funcion*)allpro.at(i)->getTipo();
                int size = item->getParams()->getTable().size();
                int count = 0 ;
                if(size==tabla_params->getTable().size()){
                    for(int j=0;j<size;j++){
                        if(tabla_params->getTable().at(j)->getTipo()->is().compare(item->getParams()->getTable().at(j)->getTipo()->is())==0){
                            count++;
                        }

                    }
                    if(count == size){
                        stringstream out;
                        out<<"Ya existe sobrecarga de funcion o procedimiento "<<lexema<<"// Fila:"<<fila<<endl;
                        throw exception(out.str().c_str());
                    }
                }
            }

        }

        Funcion *funcion = new Funcion(tabla_params,tts,tabla_funcion,intruccion);
        this->tabla_de_variables->additem(new Item_ts(funcion,lexema));
        for(int i=0;i<sizeP;i++){
            temp->additem(tabla_params->getTable().at(i));
        }
        for(int i=0;i<sizePr;i++){
            temp->additem(tabla_funcion->getTable().at(i));
        }
        for(int i=0;i<(int)this->tabla_de_variables->getTable().size();i++){
            if(temp->get(this->tabla_de_variables->getTable().at(i)->getId())==0){
                temp->additem(this->tabla_de_variables->getTable().at(i));
            }
        }
        if(intruccion!=0){
            intruccion->SetReturn(tts);
            intruccion->validarSemantica(tabla_de_tipos,temp);
        }
        delete temp;
    }else{
        stringstream out;
        out<<"Variable Ya Exite "<<lexema<<"// Fila: "<<fila <<endl;
        throw exception(out.str().c_str());
    }

}

Modo *Sintactico::MODO()
{
    int fila = token_actual->getLinea();
    int col = token_actual->getColumna();
    match(tokentype.rev_modo);
    match(tokentype.pntkeyIzq);
    vector<string>ids;
    ids =LISTAID(ids);
    match(tokentype.pntkeyDer);
    match(tokentype.pntComa);
    int tipo = TIPOSE();
    Modo *modo = new Modo(0,ids,tipo,fila,col);
    return modo;
}

Tipo_ts* Sintactico::TIPODATO(){
    int fila = this->token_actual->getLinea();
    if(token_actual->getCod()==tokentype.revEntero){
        match(tokentype.revEntero);

        return this->tabla_de_tipos->get("ENTERO")->getTipo();
    }else{
        if(token_actual->getCod()==tokentype.revReal){
            match(tokentype.revReal);
            return this->tabla_de_tipos->get("REAL")->getTipo();
        }else{
            if(token_actual->getCod()==tokentype.revCaracter){
                match(tokentype.revCaracter);
                return this->tabla_de_tipos->get("CARACTER")->getTipo();
            }else{
                if(token_actual->getCod()==tokentype.revCadena){
                    string lexema = "CADENA";
                    match(tokentype.revCadena);
                    match(tokentype.pntcorIzq);
                    string litentero = token_actual->getLexema();
                    match(tokentype.litNumeroEntero);
                    match(tokentype.pntcorDer);
                    lexema.append(litentero);
                    Item_ts *i_ts=this->tabla_de_tipos->get(lexema);
                    if(i_ts==0){
                        i_ts = new Item_ts(new Cadena(atoi( litentero.c_str()) ),lexema);
                        this->tabla_de_tipos->additem(i_ts);
                    }
                    return i_ts->getTipo();

                }else{
                    if(token_actual->getCod()==tokentype.revBooleano){
                        match(tokentype.revBooleano);
                        return this->tabla_de_tipos->get("BOOLEANO")->getTipo();
                    }else{
                        if(token_actual->getCod()==tokentype.litIdentificador){
                            string lexema = token_actual->getLexema();
                            match(tokentype.litIdentificador);
                            Item_ts *its = this->tabla_de_tipos->get(lexema);
                            if(its!=0){
                                return its->getTipo();
                            }else{
                                stringstream out;
                                out <<"TIPO no existe// Fila: "<<fila<<endl;
                                throw  exception(out.str().c_str());
                            }
                        }else{
                            stringstream out;
                            out << "Error Sintactico: Se Esperaba Tipo de Dato; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea() ;
                            throw  exception(out.str().c_str());
                        }

                    }

                }
            }
        }
    }
}

Tipo_ts* Sintactico::ARREGLO(){

    vector<TipoDato*> index;
    match(tokentype.revArreglo);
    match(tokentype.pntcorIzq);
    index = DIMS(index);
    vector<int> dims;
    for(int i=0;i<(int)index.size();i++){
        dims.push_back(atoi( index.at(i)->getValor().c_str() ));
    }
    match(tokentype.pntcorDer);
    match(tokentype.revDe);
    Tipo_ts *its = TIPODATO();

    return new Arreglo(dims,its);
}

vector<TipoDato*> Sintactico::DIMS(vector<TipoDato*> index){
    TipoDato* tipodato = DIMS_2PRI();
    index.push_back(tipodato);
    index = DIMS_PRI(index);
    return index;
}

vector<TipoDato*> Sintactico::DIMS_PRI(vector<TipoDato*> index){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        return DIMS(index);
    }else{
        return index;
    }
}

TipoDato* Sintactico::DIMS_2PRI(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.litNumeroEntero){
        TipoDato *tipodato = new TipoDato(fila,col);
        tipodato->setis(tokentype.litNumeroEntero);
        tipodato->setValor(token_actual->getLexema());
        match(tokentype.litNumeroEntero);
        return tipodato;

    }else{
        if(token_actual->getCod()==tokentype.litIdentificador){
            Variable *variable = new Variable(0,fila,col);
            variable->setValor(token_actual->getLexema());
            match(tokentype.litIdentificador);
            return variable;
        }else{
            stringstream out;
            out << "Error Sintactico: Se esperaba una literal entera o Identificador; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
            throw  exception(out.str().c_str());
        }
    }

}

vector<string> Sintactico::LISTAID(vector<string> ids){
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);
    ids.push_back(lexema);
    return LISTAID_PRI(ids);
}

vector<string> Sintactico::LISTAID_PRI(vector<string> ids){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        ids = LISTAID(ids);
    }
    return ids;
}

vector<Expr*> Sintactico::EXPRS(vector<Expr*> expr){
    expr.push_back(EXPR());
    expr = EXPRS_PRI(expr);

    return expr;
}

vector<Expr*> Sintactico::EXPRS_PRI(vector<Expr*> expr){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        expr = EXPRS(expr);
        return expr;
    }
    return expr;
}

Expr* Sintactico::EXPR(){
    return R();
}

Expr* Sintactico::R(){

    return R_PRI(E());
}

Expr* Sintactico::R_PRI(Expr* E_){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.oprMayor){
        match(tokentype.oprMayor);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprMayor);
        return expr;

    }
    if(token_actual->getCod()==tokentype.oprMayorIgual){
        match(tokentype.oprMayorIgual);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprMayorIgual);
        return expr;
    }
    if(token_actual->getCod()==tokentype.oprMenor){
        match(tokentype.oprMenor);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprMenor);
        return expr;
    }
    if(token_actual->getCod()==tokentype.oprMenorIgual){
        match(tokentype.oprMenorIgual);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprMenorIgual);
        return expr;
    }
    if(token_actual->getCod()==tokentype.oprIgual){
        match(tokentype.oprIgual);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprIgual);
        return expr;
    }
    if(token_actual->getCod()==tokentype.oprDist){
        match(tokentype.oprDist);
        ExprBinaria *expr = new ExprBinaria(E_,E(),fila,col);
        expr->setis(tokentype.oprDist);
        return expr;
    }
    return E_;
}

Expr* Sintactico::E(){
    return E_PRI(T());
}

Expr* Sintactico::E_PRI(Expr* T_){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.oprSuma){
        match(tokentype.oprSuma);
        ExprBinaria *expr = new ExprBinaria(T_,T(),fila,col);
        expr->setis(tokentype.oprSuma);
        return E_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.oprResta){
        match(tokentype.oprResta);
        ExprBinaria *expr = new ExprBinaria(T_,T(),fila,col);
        expr->setis(tokentype.oprResta);
        return E_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.oprLogicoO){
        match(tokentype.oprLogicoO);
        ExprBinaria *expr = new ExprBinaria(T_,T(),fila,col);
        expr->setis(tokentype.oprLogicoO);
        return E_PRI(expr);
    }
    return T_;

}

Expr* Sintactico::T(){

    return T_PRI(P());

}

Expr* Sintactico::T_PRI(Expr* P_){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.oprMult){
        match(tokentype.oprMult);
        ExprBinaria *expr = new ExprBinaria(P_,P(),fila,col);
        expr->setis(tokentype.oprMult);
        return T_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.oprDiv){
        match(tokentype.oprDiv);
        ExprBinaria *expr = new ExprBinaria(P_,P(),fila,col);
        expr->setis(tokentype.oprDiv);
        return T_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.oprLogicoY){
        match(tokentype.oprLogicoY);
        ExprBinaria *expr = new ExprBinaria(P_,P(),fila,col);
        expr->setis(tokentype.oprLogicoY);
        return T_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.revMod){
        match(tokentype.revMod);
        ExprBinaria *expr = new ExprBinaria(P_,P(),fila,col);
        expr->setis(tokentype.revMod);
        return T_PRI(expr);
    }
    if(token_actual->getCod()==tokentype.revDiv){
        match(tokentype.revDiv);
        ExprBinaria *expr = new ExprBinaria(P_,P(),fila,col);
        expr->setis(tokentype.revDiv);
        return T_PRI(expr);
    }

    return P_;
}

Expr* Sintactico::P(){
    return P_PRI(F());
}

Expr* Sintactico::P_PRI(Expr* F_){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.oprExpo){
        match(tokentype.oprExpo);
        ExprBinaria *expr = new ExprBinaria(F_,F(),fila,col);
        expr->setis(tokentype.oprExpo);
        return P_PRI(expr);
    }
    return F_;
}

Expr* Sintactico::F(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.litIdentificador){
        Variable *sin = VARIABLE();
        return sin;
    }else{
        if(token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter){
            return LITERAL();
        }else{
            if(token_actual->getCod()==tokentype.pntparIzq){
                match(tokentype.pntparIzq);
                Expr* r =  R();
                match(tokentype.pntparDer);
                return r;
            }else{
                if(token_actual->getCod()==tokentype.revNo){
                    match(tokentype.revNo);
                    ExprUnary *exprunary = new ExprUnary(R(),fila,col);
                    exprunary->setis(tokentype.revNo);
                    return exprunary;
                }else{
                    if(token_actual->getCod()==tokentype.oprResta){
                        match(tokentype.oprResta);
                        TipoDato *menosuno = new TipoDato(fila,col);
                        menosuno->setis(tokentype.litNumeroEntero);
                        menosuno->setValor("-1");
                        ExprBinaria * exprbinaria = new ExprBinaria(F(),menosuno,fila,col);
                        exprbinaria->setis(tokentype.oprMult);
                        return exprbinaria;
                    }else{
                        stringstream out;
                        out << "Error Sintactico: se esperaba  una varaible o una literal o parentesis; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
                        throw  exception(out.str().c_str());
                    }
                }

            }
        }
    }

}

TipoDato* Sintactico::LITERAL(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    TipoDato *tipodato = new TipoDato(fila,col);
    if(token_actual->getCod()==tokentype.litCadena){
        tipodato->setis(token_actual->getCod());
        tipodato->setValor(token_actual->getLexema());
        match(tokentype.litCadena);
        return tipodato;
    }else{
        if(token_actual->getCod()==tokentype.litNumeroReal){
            tipodato->setis(token_actual->getCod());
            tipodato->setValor(token_actual->getLexema());
            match(tokentype.litNumeroReal);
            return tipodato;
        }else{
            if(token_actual->getCod()==tokentype.revFalso){
                tipodato->setis(token_actual->getCod());
                tipodato->setValor(token_actual->getLexema());
                match(tokentype.revFalso);
                return tipodato;
            }else{
                if(token_actual->getCod()==tokentype.revVerdadero){
                    tipodato->setis(token_actual->getCod());
                    tipodato->setValor(token_actual->getLexema());
                    match(tokentype.revVerdadero);
                    return tipodato;
                }else{
                    if(token_actual->getCod()==tokentype.litNumeroEntero){
                        tipodato->setis(token_actual->getCod());
                        tipodato->setValor(token_actual->getLexema());
                        match(tokentype.litNumeroEntero);
                        return tipodato;
                    }else{
                        if(token_actual->getCod()==tokentype.litCaracter){
                            tipodato->setis(token_actual->getCod());
                            tipodato->setValor(token_actual->getLexema());
                            match(tokentype.litCaracter);
                            return tipodato;
                        }else{
                            stringstream out;
                            out << "Error Sintactico: se esperaba  una  literal; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
                            throw  exception(out.str().c_str());
                        }
                    }
                }
            }
        }
    }

}

vector<TipoDato*> Sintactico::LITERAL_PRI(vector<TipoDato*> tipodato){
    TipoDato *tipodato_ = LITERAL();
    tipodato.push_back(tipodato_);
    tipodato = LITERAL_2PRI(tipodato);
    return tipodato;
}

vector<TipoDato*> Sintactico::LITERAL_2PRI(vector<TipoDato*> tipodato){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        tipodato= LITERAL_PRI(tipodato);
        return tipodato;
    }else{
        return tipodato;
    }

}

Retorne* Sintactico::RETORNE(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    match(tokentype.revRetorne);
    Expr *expr = EXPR();
    Retorne *retorne = new Retorne(0,expr,fila,col);
    return retorne;
}

Tipo_ts* Sintactico::TIPORETORNO(){
    if(token_actual->getCod()==tokentype.revEntero || token_actual->getCod()==tokentype.revReal || token_actual->getCod()==tokentype.revCaracter|| token_actual->getCod()==tokentype.revCadena || token_actual->getCod()==tokentype.litIdentificador||token_actual->getCod()==tokentype.revBooleano ){
        return TIPODATO();
    }else{
        return ARREGLO();
    }
}

Sentencia* Sintactico::INSTRCICLO(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.revPara){
        match(tokentype.revPara);
        Asignar *asignar_ = ASIGNAR();
        match(tokentype.revHasta);
        Expr *expr_= EXPR();
        match(tokentype.revHaga);
        ENTER_PRI();
        Sentencia *instrucciones_ = INTRUCCIONES();
        ENTER_PRI();
        match(tokentype.revFin);
        match(tokentype.revPara);
        Para *para = new Para(0,asignar_,expr_,instrucciones_,fila,col);
        return para;

    }else{
        if(token_actual->getCod()==tokentype.revMientras){
            match(tokentype.revMientras);
            Expr *expr_=EXPR();
            match(tokentype.revHaga);
            ENTER_PRI();
            Sentencia *instrucciones_ =INTRUCCIONES();
            ENTER_PRI();
            match(tokentype.revFin);
            match(tokentype.revMientras);
            Mientras *mientras = new Mientras(0,expr_,instrucciones_,fila,col);
            return mientras;
        }else{
            if(token_actual->getCod()==tokentype.revRepita){
                match(tokentype.revRepita);
                ENTER_PRI();
                Sentencia *instrucciones_ =INTRUCCIONES();
                ENTER_PRI();
                match(tokentype.revHasta);
                Expr *expr_= EXPR();
                Repita *repita = new Repita(0,expr_,instrucciones_,fila,col);
                return repita;

            }else{
                stringstream out;
                out << "Error Sintactico: se esperaba un ciclo; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
                throw  exception(out.str().c_str());
            }
        }
    }
}

Sentencia* Sintactico::INSTRCONDICIONAL(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    if(token_actual->getCod()==tokentype.revSi){
        match(tokentype.revSi);
        Expr *expr_ = EXPR();
        match(tokentype.revEntonces);
        ENTER_PRI();
        Sentencia* instrucciones_ = INTRUCCIONES();
        ENTER_PRI();
        Sentencia* sino = SINO();
        match(tokentype.revFin);
        match(tokentype.revSi);
        Si *si = new Si(0,expr_,instrucciones_,sino,fila,col);
        return si;


    }else{
        if(token_actual->getCod()==tokentype.revCaso){
            match(tokentype.revCaso);
            Variable *variable = VARIABLE_PRI();
            ENTER();
            CasoList *casolist = CASO();

            Sentencia *intrucciones = FINCASO();

            Caso *caso = new Caso(0,variable,casolist,intrucciones,fila,col);
            return caso;
        }else{
            stringstream out;
            out << "Error Sintactico: se esperaba un condicional; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
            throw  exception(out.str().c_str());
        }

    }
}

void Sintactico::PARAMS(Tabla_Simbolos* ts){
    if(token_actual->getCod()==tokentype.pntparIzq){
        match(tokentype.pntparIzq);
        PARAMS_PRI(ts);
        match(tokentype.pntparDer);
    }
}

void Sintactico::PARAMS_PRI(Tabla_Simbolos* ts){
    int fila = this->token_actual->getLinea();
    Item_ts* its = PARAM_PRI();
    if(this->tabla_de_tipos->get(its->getId())==0 && ts->get(its->getId())==0){
        ts->additem(its);
    }else{
        stringstream out;
        out<<"Variable Ya Exite "<< its->getId()<<"// Fila: "<<fila<<endl;
        throw exception(out.str().c_str());
    }
    PARAMS_2PRI(ts);
}

void Sintactico::PARAMS_2PRI(Tabla_Simbolos* ts){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        PARAMS_PRI(ts);
    }
}

Item_ts* Sintactico::PARAM_PRI(){
    if(token_actual->getCod()==tokentype.revVar){
        match(tokentype.revVar);
        Item_ts *its = PARAM();
        its->setVar(true);
        return its;

    }else{
        return PARAM();
    }
}

Item_ts* Sintactico::PARAM(){
    Tipo_ts* tts = TIPORETORNO();
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);

    return new Item_ts(tts,lexema);
}

Escriba* Sintactico::ESCRIBA(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    match(tokentype.revEscriba);
    match(tokentype.pntkeyIzq);
    vector<string> ids;
    ids=LISTAID(ids);
    match(tokentype.pntkeyDer);
    match(tokentype.pntComa);
    Expr *ex = ABV();
    Escriba *escriba = new Escriba(0,ids,ex,fila,col);
    return escriba;
}

Llamar*  Sintactico::LLAMAR(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();

    match(tokentype.revLlamar);
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);
    vector<Expr*> expr = LLAMAR_PRI();
    Llamar *llamar = new Llamar(0,expr,lexema,fila,col);
    return llamar;
}

vector<Expr*> Sintactico::LLAMAR_PRI(){
    if(token_actual->getCod()==tokentype.pntparIzq){
        match(tokentype.pntparIzq);
        vector<Expr*> expr = LLAMAR_2PRI();
        match(tokentype.pntparDer);
        return expr;
    }else{
        vector<Expr*> expr;
        return expr ;
    }
}

vector<Expr*> Sintactico::LLAMAR_2PRI(){
    vector<Expr*> expr;
    if(token_actual->getCod()==tokentype.litIdentificador || token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter || token_actual->getCod()==tokentype.pntparIzq || token_actual->getCod()==tokentype.revNo || token_actual->getCod()==tokentype.oprResta){
        expr = EXPRS(expr);

    }
    return expr;

}

Lea* Sintactico::LEA(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    match(tokentype.revLea);
    match(tokentype.pntkeyIzq);
    vector<string> variables;
    variables = LISTAID(variables);
    match(tokentype.pntkeyDer);
    match(tokentype.pntComa);
    Variable *var=VARIABLE();
    Lea *lea = new Lea(0,variables,var,fila,col);
    return lea;

}

vector<Variable*> Sintactico::LISTAVARIABLES(vector<Variable*> variables){
    variables.push_back(VARIABLE_PRI());
    variables = LISTAVARIABLES_PRI(variables);
    return variables;
}

vector<Variable*> Sintactico::LISTAVARIABLES_PRI(vector<Variable*> variables){
    if(token_actual->getCod()==tokentype.pntComa){
        match(tokentype.pntComa);
        return LISTAVARIABLES(variables);
    }else{
        return variables;
    }
}

Asignar* Sintactico::ASIGNAR(){
    Variable *variable = VARIABLE_PRI();
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    match(tokentype.oprAsig);
    Asignar *asignar = new Asignar(0,variable,EXPR(),fila,col);
    return asignar;
}

Variable* Sintactico::VARIABLE(){
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);
    Variable *variable = VARIABLE_4PRI();
    variable->setSig(VARIABLE_3PRI());
    variable->setValor(lexema);
    return variable;
}

Variable* Sintactico::VARIABLE_PRI(){
    string lexema = token_actual->getLexema();
    match(tokentype.litIdentificador);
    Variable *variable = VARIABLE_2PRI();
    variable->setSig(VARIABLE_3PRI());
    variable->setValor(lexema);
    return variable;
}

Variable* Sintactico::VARIABLE_2PRI(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    Variable *variable;
    if(token_actual->getCod()==tokentype.pntcorIzq){
        match(tokentype.pntcorIzq);
        vector<Expr*> index;
        index = EXPRS(index);
        match(tokentype.pntcorDer);
        variable = new IndexVariable(0,index,fila,col);

        return variable;
    }else{

        return variable = new Variable(0,fila,col);

    }
}

Variable* Sintactico::VARIABLE_3PRI(){
    if(token_actual->getCod()==tokentype.pntPunto){
        match(tokentype.pntPunto);
        return VARIABLE_PRI();
    }else{
        return 0;
    }
}

Variable* Sintactico::VARIABLE_4PRI(){
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getColumna();
    Variable *variable;
    if(token_actual->getCod()==tokentype.pntparIzq){
        match(tokentype.pntparIzq);
        vector<Expr*>exprs= LLAMAR_2PRI();
        match(tokentype.pntparDer);
        variable = new VariableFuncion(0,exprs,fila,col);
        return variable;
    }
    if(token_actual->getCod()==tokentype.pntcorIzq){
        match(tokentype.pntcorIzq);
        vector<Expr*> index;
        index = EXPRS(index);
        match(tokentype.pntcorDer);

        variable = new IndexVariable(0,index,fila,col);
        return variable;
    }

    if(token_actual->getCod()==tokentype.pntkeyIzq){
        match(tokentype.pntkeyIzq);
        vector<Expr*> rango;

        rango = RANGO(rango);

        match(tokentype.pntkeyDer);

        variable = new PinVariable(0,rango.at(0),rango.at(1),fila,col);

        return variable;
    }

    return variable = new Variable(0,fila,col);
}

vector<Expr *> Sintactico::RANGO(vector<Expr *> rango)
{
    rango.push_back(EXPR());
    rango = MORERANGO(rango);
    return rango;
}

vector<Expr *> Sintactico::MORERANGO(vector<Expr *> rango)
{
    if(this->token_actual->getCod()==this->tokentype.pntDosPuntos){
        match(tokentype.pntDosPuntos);
        rango.push_back(EXPR());
    }else{
        rango.push_back(0);
    }

    return rango;
}

Sentencia* Sintactico::SINO(){
    if(token_actual->getCod()==tokentype.revSino){
        match(tokentype.revSino);
        ENTER_PRI();
        Sentencia *sentencia = INTRUCCIONES();
        ENTER_PRI();
        return sentencia;
    }else{
        return 0;
    }
}

Sentencia* Sintactico::FINCASO(){
    Sentencia *instruccion = 0;
    if(token_actual->getCod()==tokentype.revSino){
        match(tokentype.revSino);
        match(tokentype.pntDosPuntos);
        ENTER_PRI();
        instruccion= INTRUCCIONES();
        ENTER_PRI();

    }
    match(tokentype.revFin);
    match(tokentype.revCaso);
    return instruccion;
}

CasoList* Sintactico::CASO(){
    vector<TipoDato*> tipodato;
    tipodato = LITERAL_PRI(tipodato);
    match(tokentype.pntDosPuntos);
    ENTER_PRI();
    Sentencia *instrucciones = INTRUCCIONES();
    ENTER_PRI();
    CasoList *casolist = new CasoList(0,tipodato,instrucciones);
    if(token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter){
        casolist->setNext(CASO());
        return casolist;
    }else{
        return casolist;
    }
}

Sentencia* Sintactico::INTRUCCIONES(){
    if(token_actual->getCod()==tokentype.litIdentificador || token_actual->getCod()==tokentype.revPara || token_actual->getCod()==tokentype.revMientras || token_actual->getCod()==tokentype.revRepita || token_actual->getCod()==tokentype.revSi || token_actual->getCod()==tokentype.revCaso || token_actual->getCod()==tokentype.revEscriba || token_actual->getCod()==tokentype.revRetorne || token_actual->getCod()==tokentype.revLlamar || token_actual->getCod()==tokentype.revLea ||token_actual->getCod()==tokentype.rev_modo|| token_actual->getCod()==tokentype.enter  ){
        Sentencia *sentencia =INSTRUCCION();
        ENTER_PRI();
        sentencia->setNext( INTRUCCIONES());
        ENTER_PRI();
        return sentencia;
    }else{
        return 0;
    }
}

Sentencia* Sintactico::INSTRUCCION(){
    if(token_actual->getCod()==tokentype.litIdentificador){
        Asignar *asiganar=ASIGNAR();
        ENTER();
        return asiganar;
    }else{
        if(token_actual->getCod()==tokentype.revPara || token_actual->getCod()==tokentype.revMientras || token_actual->getCod()==tokentype.revRepita){
            Sentencia *sentencia = INSTRCICLO();
            ENTER();
            return sentencia;
        }else{
            if(token_actual->getCod()==tokentype.revSi || token_actual->getCod()==tokentype.revCaso){
                Sentencia *sentencia = INSTRCONDICIONAL();
                ENTER();
                return sentencia;
            }else{
                if(token_actual->getCod()==tokentype.revEscriba){
                    Escriba *escriba = ESCRIBA();
                    ENTER();
                    return escriba;
                }else{
                    if(token_actual->getCod()==tokentype.revRetorne ){
                        Retorne *retorne = RETORNE();
                        ENTER();
                        return retorne;
                    }else{
                        if(token_actual->getCod()==tokentype.revLlamar){
                            Llamar *llamar =LLAMAR();
                            ENTER();
                            return llamar;
                        }else{
                            if(token_actual->getCod()==tokentype.revLea){
                                Lea* lea =LEA();
                                ENTER();
                                return lea;
                            }else{
                                if(token_actual->getCod()==tokentype.rev_modo){
                                    Modo* modo = MODO();
                                    ENTER();
                                    return modo;
                                }else{
                                    return 0;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void Sintactico::print(Sentencia *sente){
    cout<<sente->is()<<endl;
    Asignar *asi = (Asignar*)sente;
    cout<<asi->getExpr()->is()<<endl;
    cout<<asi->getVariable()->is()<<endl;

}

Tabla_Simbolos *Sintactico::getTablaVaribales()
{
    return this->tabla_de_variables;
}

Tabla_Simbolos *Sintactico::getTablaTipos()
{
    return this->tabla_de_tipos;
}

int Sintactico::TIPOSE()
{
    if(token_actual->getCod()==this->tokentype.rev_entrada){
        match(tokentype.rev_entrada);
        return 1;
    }else{
        match(tokentype.rev_salida);
        return 0;
    }
}

Expr *Sintactico::ABV()
{
    int fila = this->token_actual->getLinea();
    int col = this->token_actual->getCod();
    if(this->token_actual->getCod()==this->tokentype.rev_bajo){
        match(tokentype.rev_bajo);
        TipoDato *tipodato = new TipoDato(fila,col);
        tipodato->setis(tokentype.litNumeroEntero);
        tipodato->setValor("0");
        return tipodato;

    }else if(this->token_actual->getCod()==this->tokentype.rev_alto){
        match(tokentype.rev_alto);
        TipoDato *tipodato = new TipoDato(fila,col);
        tipodato->setis(tokentype.litNumeroEntero);
        tipodato->setValor("1");
        return tipodato;
    }if(this->token_actual->getCod()==this->tokentype.litIdentificador){
        return VARIABLE();
    }else{
        stringstream out;
        out << "Se esperaba token ALTO,BAJO, o varaible" <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Fila: "<<token_actual->getLinea();
        throw  exception(out.str().c_str());
    }
}
